package jalgebrava.group.groups;

import jalgebrava.group.Group;
import jalgebrava.group.morphisms.Automorphism;
import jalgebrava.group.morphisms.Homomorphism;
import jalgebrava.util.Pair;
import jalgebrava.util.collections.IterableUtil;

class SemidirectProductFactory {
	final static <G,H> Group<Pair<G,H>> mk(final Group<G> g, final Group<H> h, 
			final Homomorphism<H, Automorphism<G>> phi) {
		return new AbstractGroup<Pair<G,H>>(g.getDescription() + "|x_{" + phi + "}" + h.getDescription(),
				IterableUtil.cartesianProduct(g, h), g.size() * h.size()) {

					@Override
					public boolean contains(Pair<G, H> x) {
						return g.contains(x.a) && h.contains(x.b);
					}

					@Override
					public Pair<G, H> inv(Pair<G, H> x) {
						G xainv = g.inv(x.a);
						H xbinv = h.inv(x.b);
						// (xa,xb)^_1 = (phi(xb^-1)(xa^-1), xb^-1
						return Pair.pair(phi.apply(xbinv).apply(xainv),xbinv);
					}

					@Override
					public Pair<G, H> mul(Pair<G, H> x, Pair<G, H> y) {
						// (xa, xb) * (ya, yb) =
						// xa * phi(xb)(ya) , xb * yb 
						return Pair.pair(g.mul(x.a, phi.apply(x.b).apply(y.a)), 
								h.mul(x.b, y.b));
					}

					@Override
					public Pair<G, H> unit() {
						return Pair.pair(g.unit(), h.unit());
					}
			
		};
	}
}
